/* eslint-disable no-param-reassign */
import incomingEventTypes from './eventTypes';
import outgoingEventTypes from '../outgoing/eventTypes';
import Group from '../../models/group';
import { getRedisUserChannelKey, getRedisGroupChannelKey } from '../../common/constant';
import { createRedisClient } from '../../../components/redis';
import { onlineCounter } from '../../../components/metrics';


import {
  REDIS_SYSTEM_CHANNEL,
  REDIS_SKYNET_LOGIN,
  REDIS_SKYNET_LOGOUT,
  REDIS_JANUS_LOGIN,
  REDIS_JANUS_LOGOUT,
  URGENT_TEACHER_REPLACEMENT,
} from '../../common/redisChannels';

class LoginHandler {
  static async handle({ ctx, emitter }) {
    if (ctx.socket.logined) return;

    const userRedisClient = createRedisClient();
    await LoginHandler.initRedisSubscribe(ctx, userRedisClient);
    await LoginHandler.initRedisPubEvents(ctx, userRedisClient, emitter);

    ctx.socket.redis_sub = userRedisClient;
    ctx.socket.logined = true;
    ctx.socket.user = {
      userId: ctx.viewer.id,
      jiuquId: ctx.viewer.jiuquId,
    };

    ctx.onlineStatusLogger.info(`${ctx.viewer.jiuquId} LOGINED`);

    // 同时保存jiuquId与userId
    ctx.redis.hset('user:online', ctx.viewer.jiuquId, ctx.viewer.id.toString());
    ctx.redis.hset('user:online:socket', ctx.viewer.jiuquId, ctx.socket.id);
    ctx.socket.emit(outgoingEventTypes.LOGGED_IN, ctx.viewer);

    // 广播用户登录
    ctx.redis.publish(REDIS_SYSTEM_CHANNEL, JSON.stringify({
      event: outgoingEventTypes.USER_LOGIN,
      payload: {
        userId: ctx.viewer.id.toString(),
        jiuquId: ctx.viewer.jiuquId,
      },
    }));
    onlineCounter.inc();

    ctx.logger.info(`${ctx.socket.id} >>> LOGIN "USER ${ctx.viewer._id}(${ctx.viewer.username})" success`);
  }

  static async initRedisPubEvents(ctx, userRedisClient, emitter) {
    userRedisClient.on(incomingEventTypes.MESSAGE, (topic, payload) =>
      emitter.handleRedisMessage(topic, payload, ctx));
  }

  static async initRedisSubscribe(ctx, userRedisClient) {
    const group = await Group.findById(ctx.viewer.group).populate('responseGroups');
    // 用户channel
    const userChannelsTopics = ctx.viewer.channels.map(getRedisUserChannelKey);
    // 用户响应组channel
    const responseGroupChannelTopics = group.responseGroups.map(g => getRedisGroupChannelKey(g.id));

    // NOTICE channel
    const additionTopics = [
      REDIS_SYSTEM_CHANNEL,
      ctx.viewer.getRedisUserNoticeChannelName(),
    ];

    if (!group.isTeacherGroup()) {
      additionTopics.push(
        REDIS_SKYNET_LOGIN,
        REDIS_SKYNET_LOGOUT,
        REDIS_JANUS_LOGIN,
        REDIS_JANUS_LOGOUT,
        URGENT_TEACHER_REPLACEMENT,
      );
    }

    const topics = [...userChannelsTopics, ...responseGroupChannelTopics, ...additionTopics];
    return Promise.all(topics.map(t => userRedisClient.subscribe(t)));
  }
}

export default LoginHandler;
